package com.tiance.demo.service.mysql.analyzer;

import com.tiance.demo.service.mysql.analyzer.pageindex.IndexPageHeaderAnalyzer;
import com.tiance.demo.service.mysql.analyzer.pageindex.InfimumAnalyzer;
import com.tiance.demo.service.mysql.analyzer.pageindex.SupremumAnalyzer;
import com.tiance.demo.service.mysql.analyzer.pageindex.UserRecordAnalyzer;
import com.tiance.demo.service.mysql.analyzer.pageundolog.UndoLogPageHeaderAnalyzer;
import com.tiance.demo.service.mysql.analyzer.pageundolog.UndoLogSegmentAnalyzer;
import com.tiance.demo.service.mysql.bo.FileHeader;
import com.tiance.demo.service.mysql.bo.FileTailer;
import com.tiance.demo.service.mysql.bo.Page;
import com.tiance.demo.service.mysql.bo.pageindex.*;
import com.tiance.demo.service.mysql.bo.pageundolog.PageUndoLog;
import com.tiance.demo.service.mysql.bo.pageundolog.UndoLogPageHeader;
import com.tiance.demo.service.mysql.bo.pageundolog.UndoLogSegmentHeader;
import com.tiance.demo.service.mysql.utils.ByteUtils;

public class PageAnalyzer {

    public static String getHexStringOf(Page page) {
        byte[] bytes = page.getBytes();
        return ByteUtils.bytes2HexStr(bytes);
    }

    public static Page analyse(byte[] bytes) {
        int offset = 0;

        Page page;

        //File Header
        byte[] fileHeaderBytes = new byte[FileHeader.SIZE];
        System.arraycopy(bytes, offset, fileHeaderBytes, 0, FileHeader.SIZE);
        FileHeader fileHeader = FileHeaderAnalyzer.analyse(fileHeaderBytes);
        offset += FileHeader.SIZE;

        switch (fileHeader.getType()) {
            case Page.FIL_PAGE_INDEX: {
                page = new PageIndex(bytes);
                analyseIndexPage(page, bytes, offset);
                break;
            }
            case Page.FIL_PAGE_UNDO_LOG: {
                page = new PageUndoLog(bytes);
                analyseUndoLogPage(page, bytes, offset);
                break;
            }
            default: {
                page = new Page(bytes);
                // 很多页类型可能不会马上实现, 所以先给一个默认实现
            }

        }
        page.setFileHeader(fileHeader);

        //File Tailer
        byte[] fileTailerBytes = new byte[FileTailer.SIZE];
        System.arraycopy(bytes, FileTailer.OFFSET_START, fileTailerBytes, 0, FileTailer.SIZE);
        FileTailer fileTailer = FileTailerAnalyzer.analyse(fileTailerBytes);
        page.setFileTailer(fileTailer);

        return page;
    }

    private static void analyseIndexPage(Page page, byte[] bytes, int offset) {
        PageIndex indexPage = (PageIndex) page;
        //解析page header
        byte[] pageHeaderBytes = new byte[IndexPageHeader.SIZE];
        System.arraycopy(bytes, offset, pageHeaderBytes, 0, IndexPageHeader.SIZE);

        IndexPageHeader indexPageHeader = IndexPageHeaderAnalyzer.analyse(pageHeaderBytes);
        indexPage.setIndexPageHeader(indexPageHeader);
        offset += IndexPageHeader.SIZE;

        //解析Infimum
        byte[] infimumBytes = new byte[Infimum.SIZE];
        System.arraycopy(bytes, offset, infimumBytes, 0, Infimum.SIZE);

        Infimum infimum = InfimumAnalyzer.analyse(infimumBytes);
        indexPage.setInfimum(infimum);
        offset += Infimum.SIZE;

        //解析Supremum
        byte[] supremumBytes = new byte[Supremum.SIZE];
        System.arraycopy(bytes, offset, supremumBytes, 0, Infimum.SIZE);

        Supremum supremum = SupremumAnalyzer.analyse(supremumBytes);
        indexPage.setSupremum(supremum);
        offset += Infimum.SIZE;

        //解析UserRecord
        int validUserRecordSize = indexPageHeader.getHeapTop();
        byte[] userRecordSize = new byte[validUserRecordSize];
        System.arraycopy(bytes, offset, userRecordSize, 0, validUserRecordSize);

        UserRecord userRecord = UserRecordAnalyzer.analyse(userRecordSize);
        indexPage.setUserRecord(userRecord);
    }

    private static void analyseUndoLogPage(Page page, byte[] bytes, int offset) {
        PageUndoLog undoLogPage = (PageUndoLog) page;
        //解析page header
        byte[] pageHeaderBytes = new byte[UndoLogPageHeader.SIZE];
        System.arraycopy(bytes, offset, pageHeaderBytes, 0, UndoLogPageHeader.SIZE);

        UndoLogPageHeader undoLogPageHeader = UndoLogPageHeaderAnalyzer.analyse(pageHeaderBytes);
        undoLogPage.setUndoLogPageHeader(undoLogPageHeader);
        offset += UndoLogPageHeader.SIZE;

        //解析segment header
        byte[] segmentHeaderBytes = new byte[UndoLogSegmentHeader.SIZE];
        System.arraycopy(bytes, offset, segmentHeaderBytes, 0, UndoLogSegmentHeader.SIZE);

        UndoLogSegmentHeader undoLogSegmentHeader = UndoLogSegmentAnalyzer.analyse(pageHeaderBytes);
        undoLogPage.setUndoLogSegmentHeader(undoLogSegmentHeader);
        offset += UndoLogSegmentHeader.SIZE;


        //TODO 继续解析细节
    }
}




